package com.bjb.vr.auth.security;

import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bjb.vr.auth.bo.UmsUserDetail;
import com.bjb.vr.common.constant.*;
import com.bjb.vr.common.dto.SysConfig;
import com.bjb.vr.common.dto.SysLogin;
import com.bjb.vr.common.dto.UmsAccount;
import com.bjb.vr.common.dto.UmsOptAccount;
import com.bjb.vr.common.mapper.SysConfigMapper;
import com.bjb.vr.common.result.CommonResult;
import com.bjb.vr.common.service.SysLoginService;
import com.bjb.vr.common.service.UmsAccountService;
import com.bjb.vr.common.service.UmsOptAccountService;
import com.bjb.vr.common.utils.JwtTokenUtil;
import com.bjb.vr.common.utils.RedisUtil;
import com.bjb.vr.common.utils.ThreadLocalUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录成功处理器
 *
 * @version 1.0.0
 * @author: HuJingBo
 * @time: 2022/4/8 10:11
 */
@Slf4j
@Component
public class RequestAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Resource
    private SysLoginService sysLoginService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private UmsAccountService umsAccountService;

    @Resource
    private UmsOptAccountService optAccountService;

    @Resource
    private SysConfigMapper sysConfigMapper;


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        log.info("用户:[{}] 登录成功！", authentication.getName());
        UmsUserDetail principal = (UmsUserDetail) authentication.getPrincipal();
        JSONObject jsonObject = null;

        // 判断用户端类型
        if (LoginConstant.MANAGER.equals(principal.getLoginType())) {
            jsonObject = buildManagerLoginInfo(request, principal);
        } else {
            jsonObject = buildOperationLoginInfo(request, principal);
        }

        // 返回结果
        CommonResult commonResult = CommonResult.Ok("登录成功").setResult(jsonObject);
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write(new ObjectMapper().writeValueAsString(commonResult));
    }

    /**
     * 封装运营端登录信息
     *
     * @param request
     * @param principal
     * @return
     */
    private JSONObject buildOperationLoginInfo(HttpServletRequest request, UmsUserDetail principal) {
        // 获取Token
        String username = principal.getUsername();
        String tenantId = principal.getTenantId();
        String loginType = principal.getLoginType();
        Long userId = principal.getUserId();
        String refreshTokenId = SecureUtil.md5(username).toUpperCase();
        String token = (String) redisUtil.hget(TokenConstants.LOGIN_OPT_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_MAP_KEY);
        if (StringUtils.isEmpty(token)) {
            token = JwtTokenUtil.createJWT(username, tenantId, loginType);
        } else {
            CommonResult commonResult = JwtTokenUtil.validateJWT(token);
            if (!commonResult.isSuccess()) {
                token = JwtTokenUtil.createJWT(username, tenantId, loginType);
            }
        }

        // 查询用户信息并存入redis
        LambdaQueryWrapper<UmsOptAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UmsOptAccount::getUsername, username);
        UmsOptAccount optAccount = optAccountService.getOne(queryWrapper);

        // 数据放入redis
        redisUtil.hset(TokenConstants.LOGIN_OPT_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_MAP_KEY, token);
        redisUtil.hset(TokenConstants.LOGIN_OPT_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_USERNAME, optAccount);
        redisUtil.expire(TokenConstants.LOGIN_OPT_TOKEN_KEY + refreshTokenId, TokenConstants.EXPIRATION, TimeUnit.MINUTES);

        // 更新数据库
        LocalDateTime loginTime = LocalDateTime.now();
        optAccountService.updateLoginTime(username, loginTime);

        // 保存到系统登录表
        Map<String, String> parameters = (Map<String, String>) ThreadLocalUtil.get(ThreadLocalConstant.REQUEST_BODY);
        SysLogin sysLogin = new SysLogin();
        sysLogin.setLoginPlatform(LoginTypeEnum.valueOf(loginType.toUpperCase()).getLoginTypeValue());
        sysLogin.setTenantId(tenantId);
        sysLogin.setAccountId(userId);
        sysLogin.setUserName(username);
        sysLogin.setStatus(LoginConstant.LOGIN_SUCCESS);
        sysLogin.setIpaddr(parameters.get(ThreadLocalConstant.USER_HOST));
        sysLogin.setAccessTime(loginTime);
        sysLogin.setMsg(LoginConstant.LOGIN_SUCCESS_MSG);
        sysLoginService.saveLoginInfo(sysLogin);

        // 查询系统版本信息
        SysConfig sysConfig = sysConfigMapper.selectOne(new LambdaQueryWrapper<>());

        // 封装返回数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(TokenConstants.TOKEN_MAP_KEY, token);
        jsonObject.put(TokenConstants.REFRESH_TOKEN_MAP_KEY, refreshTokenId);
        jsonObject.put(Constants.SYSTEM_OPT_VERSION, sysConfig.getVersion());
        jsonObject.put(Constants.REQUIRE_CHANGE_PASS, principal.isRequireChangePass());
        return jsonObject;
    }

    /**
     * 封装教师端登录信息
     *
     * @param request
     * @param principal
     * @return
     */
    private JSONObject buildManagerLoginInfo(HttpServletRequest request, UmsUserDetail principal) {
        // 获取Token
        String username = principal.getUsername();
        String tenantId = principal.getTenantId();
        String loginType = principal.getLoginType();
        Long userId = principal.getUserId();
        String refreshTokenId = SecureUtil.md5(username).toUpperCase();
        String token = (String) redisUtil.hget(TokenConstants.LOGIN_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_MAP_KEY);
        if (StringUtils.isEmpty(token)) {
            token = JwtTokenUtil.createJWT(username, tenantId, loginType);
        } else {
            CommonResult commonResult = JwtTokenUtil.validateJWT(token);
            if (!commonResult.isSuccess()) {
                token = JwtTokenUtil.createJWT(username, tenantId, loginType);
            }
        }

        // 查询用户信息并存入redis
        LambdaQueryWrapper<UmsAccount> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UmsAccount::getUsername, username);
        UmsAccount umsAccount = umsAccountService.getOne(queryWrapper);

        // 数据放入redis
        redisUtil.hset(TokenConstants.LOGIN_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_MAP_KEY, token);
        redisUtil.hset(TokenConstants.LOGIN_TOKEN_KEY + refreshTokenId, TokenConstants.TOKEN_USERNAME, umsAccount);
        redisUtil.expire(TokenConstants.LOGIN_TOKEN_KEY + refreshTokenId, TokenConstants.EXPIRATION, TimeUnit.MINUTES);

        // 更新数据库
        // 更新数据库
        LocalDateTime loginTime = LocalDateTime.now();
        umsAccountService.updateLoginTime(username,loginTime);

        // 保存到系统登录表
        Map<String, String> parameters = (Map<String, String>) ThreadLocalUtil.get(ThreadLocalConstant.REQUEST_BODY);
        SysLogin sysLogin = new SysLogin();
        sysLogin.setLoginPlatform(LoginTypeEnum.valueOf(loginType.toUpperCase()).getLoginTypeValue());
        sysLogin.setTenantId(tenantId);
        sysLogin.setAccountId(userId);
        sysLogin.setUserName(username);
        sysLogin.setStatus(LoginConstant.LOGIN_SUCCESS);
        sysLogin.setIpaddr(parameters.get(ThreadLocalConstant.USER_HOST));
        sysLogin.setAccessTime(loginTime);
        sysLogin.setMsg(LoginConstant.LOGIN_SUCCESS_MSG);
        sysLoginService.saveLoginInfo(sysLogin);

        // 查询系统版本信息
        SysConfig sysConfig = sysConfigMapper.selectOne(new LambdaQueryWrapper<>());

        // 封装返回数据
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(TokenConstants.TOKEN_MAP_KEY, token);
        jsonObject.put(TokenConstants.REFRESH_TOKEN_MAP_KEY, refreshTokenId);
        jsonObject.put(Constants.SYSTEM_VERSION, sysConfig.getVersion());
        jsonObject.put(Constants.REQUIRE_CHANGE_PASS, principal.isRequireChangePass());
        return jsonObject;
    }
}
